/////////////////////
// Configuration
/////////////////////


String.prototype.trim = function () {
    return this.replace(
        /^\s*(\S*(\s+\S+)*)\s*$/, "$1"); 
}; 

function $(id) {
	return document.getElementById(id);
}

var _DEBUG=false;

function _error_debug(msg)
{
	if(!_DEBUG) {
		return;
	}

	if(window.console) {
		window.console.log(msg);
	} else {
		alert(msg);
	}
}

var day = (new Date()).getDay();
var upcomingArrive;
var nextArrive;

var station_list = [];

var line;
var direction;
var station;
var station_short_name;

var widgetTimeout;
var frontShowing = true;

function setup()
{

	$('flipBack').onclick = showBack;
	$('flipFront').onclick = showFront;
	$('front').onmouseover = showFlip;
	$('front').onmouseout = hideFlip;
	
	$('flipBack').onmouseover = function () {
		$('fliprollie').style.opacity = .25;
		};
	
	$('flipBack').onmouseout = function () {
		$('fliprollie').style.opacity = 0;
		};
	
	$('line').onchange = function () {
		line = this.value;
		if(req.readyState > 0) {
			req.abort();
		}
		$('station').options.length = 0;
		station_list = [];
		fetchSchedule();
		};

	$('direction').onchange = function () {
		direction = this.value;
		if(req.readyState > 0) {
			req.abort();
		}
		$('station').options.length = 0;
		station_list = [];
		fetchSchedule();
		};

	$('station').onchange = function () {
		station = this.value;
		station_short_name = station_list[this.value]["short_name"];
		};

	if(window.widget) {
		line = widget.preferenceForKey(createPrefKey("line"));
		direction = widget.preferenceForKey(createPrefKey("direction"));
		station = widget.preferenceForKey(createPrefKey("station"));
	}

	$('line').options[$('line').options.length] = new Option('Alum Rock to Santa Teresa', '901', (line=='901'));
	$('line').options[$('line').options.length] = new Option('Mountain View to Winchester', '902', (line=='902'));
	$('line').options[$('line').options.length] = new Option('Ohlone/Chynoweth to Almaden', '900', (line=='900'));

	$('direction').options[$('direction').options.length] = new Option('<-- Northbound', 'NO', (direction=='NO'));
	$('direction').options[$('direction').options.length] = new Option('--> Southbound', 'SO', (direction=='SO'));

	line = $('line').value;
	direction = $('direction').value;
	
	$('arrivalTime').innerHTML = "Downloading...";
	fetchSchedule();

	if(window.widget) {
		window.widget.onshow = function() {
			widgetTimeout = setTimeout("updateWidget()",1000);
			};
		window.widget.onhide = function() {
			if(widgetTimeout) {
				clearTimeout(widgetTimeout);
			}
			widgetTimeout = null;
			};
	} else {
		setTimeout("updateNonWidget()",5000);
	}
}

function updateWidget()
{
	if(frontShowing == true) {
		updateFront();
	}
	widgetTimeout = setTimeout("updateWidget()",1000);
}

function updateNonWidget()
{
	_error_debug('updateNonWidget()');

	if(frontShowing == true && station_list && station) {
		updateFront();
	}
	setTimeout("updateNonWidget()",5000);
}

function showFlip()
{
	$('flipBack').style.opacity = 1;
}

function hideFlip()
{
	$('flipBack').style.opacity = 0;
	$('fliprollie').style.opacity = 0;
}

function showBack()
{
	frontShowing = false;
	
	setTimeout("$('front').style.display = 'none'",0);
	setTimeout("$('back').style.display = 'block'",0);
	if(window.widget) {
		widget.resizeAndMoveTo (window.screenX, window.screenY, 350, 160);
		widget.prepareForTransition("ToBack");
		setTimeout("widget.performTransition();", 0);
	}
}

function showFront()
{
	frontShowing = true;
	
	updateStaticFront();
	updateFront();

	// do the flip
	setTimeout("$('front').style.display = 'block'",0);
	setTimeout("$('back').style.display = 'none'",0);
	if(window.widget) {
		setTimeout("widget.resizeAndMoveTo (window.screenX, window.screenY, 350, 73)",0);
		widget.prepareForTransition("ToFront");
		setTimeout("widget.performTransition();", 0);
	}

	// save the prefs
	updatePrefs();
	
}

var req;

function fetchSchedule(url) {
	_error_debug('fetchSchedule()');

	var url = 'http://www.vta.org/schedules/tdl/SC_' + line + direction + '_' + 'WK' + '.tdl';

	req = new XMLHttpRequest();
	req.overrideMimeType("text/plain");
	req.open("GET", url);
	req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
	req.setRequestHeader("Cache-Control", "no-cache");
	var params = "";
	req.send(params);
	req.onreadystatechange = fetchSchedule_WK_stateChanged;
}

function fetchSchedule_WK_stateChanged()
{
	_error_debug('server_request_WK_stateChanged(): state=' + req.readyState + ', status=' + req.status);

	if(req.readyState == 4) {
		if(req.status == 200) {
			parseData(req.responseText, 'WK');

			var url = 'http://www.vta.org/schedules/tdl/SC_' + line + direction + '_' + 'SA' + '.tdl';

			req = new XMLHttpRequest();
			req.overrideMimeType("text/plain");
			req.open("GET", url);
			req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
			req.setRequestHeader("Cache-Control", "no-cache");
			var params = "";
			req.send(params);
			req.onreadystatechange = fetchSchedule_SA_stateChanged;
		} else {
			fetchSchedule_failed();
		}
	}
}

function fetchSchedule_SA_stateChanged()
{
	_error_debug('server_request_SA_stateChanged(): state=' + req.readyState + ', status=' + req.status);

	if(req.readyState == 4) {
		if(req.status == 200) {
			parseData(req.responseText, 'SA');

			var url = 'http://www.vta.org/schedules/tdl/SC_' + line + direction + '_' + 'SU' + '.tdl';

			req = new XMLHttpRequest();
			req.overrideMimeType("text/plain");
			req.open("GET", url);
			req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
			req.setRequestHeader("Cache-Control", "no-cache");
			var params = "";
			req.send(params);
			req.onreadystatechange = fetchSchedule_SU_stateChanged;
		} else {
			fetchSchedule_failed();
		}
	}
}

function fetchSchedule_SU_stateChanged()
{
	_error_debug('server_request_SU_stateChanged(): state=' + req.readyState + ', status=' + req.status);

	if(req.readyState == 4) {
		if(req.status == 200) {
			parseData(req.responseText, 'SU');
			updateStationList();
			updateStaticFront();
			updateFront();
		} else {
			fetchSchedule_failed();
		}
	}
}

function fetchSchedule_failed(responseText)
{
	$('arrivalTime').innerHTML = "Failed";
}

function parseData(raw_data, which_day)
{
	_error_debug('parseData(' + which_day + ')');

	var stationStr = raw_data.substring(raw_data.search(/[A-Z]{3}/g),raw_data.search(/\n\n[A-Z]{3}/g));
	var stationArr = stationStr.split("\n");
	
	_error_debug('stationArr.length=' + stationArr.length);

	var station_list_idx = [];

	// get the list of stations from the top of the document
	for(var i in stationArr) {
		if(!stationArr.hasOwnProperty(i)) continue;

		var stn = stationArr[i].split("\t");
		if(!stn[1]) continue;

		var handled_station = false;
		
//		_error_debug("looking for " + stn[0]);
		
		// find the matching station in the main list
		for(var j in station_list) {
			if(!station_list.hasOwnProperty(j)) continue;
			
			if(station_list[j]["short_name"] == stn[0]) {
				// for stations that already exist in the main list, add the new time points
				station_list_idx[i] = j;
//				_error_debug('new ' + i + ' mapped to real ' + j);
				handled_station = true;
				break;
			}
		}

		if(handled_station == false) {

			for(var k = station_list.length; k > i; k--) {
				station_list[k] = station_list[k-1];
			}
			station_list_idx[i] = k;
			station_list[k] = {
				"name" : stn[1].trim()
					.replace("Sta.","Station")
					.replace("Ctr.","Center")
					.replace("Lr Station","Light Rail Station"),
				"short_name" : stn[0],
				"time_points" : [[], [], [], [], [], [], []]
				};
		}
	}

	_error_debug("Stations found: " + station_list.length);

	// get all of the remaining lines of the document
	var timesStr = raw_data.substring(raw_data.search(/\t\n/g)+2,raw_data.length);
//	_error_debug('timesStr.length=' + timesStr.length);
	var lines = timesStr.split("\n");
//	_error_debug('lines.length=' + lines.length);
	
	var station_current_mins = [];
	for(i in station_list) {
		station_current_mins[i] = 0;
	}
	
	var first_time_of_prev_row = 0;
	var first_time_of_this_row;

	// process each line, putting each time point in the corresponding station
	for(var i in lines) {
		if(!lines.hasOwnProperty(i)) continue;

//		_error_debug('line #' + i + '=' + lines[i]);
		var timelist = lines[i].split("\t");
//		_error_debug('line #' + i + ' timelist.length=' + timelist.length);

		var prev_time = 0;
		var into_tomorrow = false;

		if(timelist.length >= station_list.length) {
			for(var j in timelist) {
				if(!timelist.hasOwnProperty(j)) continue;
				if(j >= station_list.length) continue;
				
				var station = station_list[station_list_idx[j]];
//				_error_debug(j + ": " + station_list[j]["name"]);

				// turn the time string into the number of minutes since midnight
				var t = timelist[j].match(/(\d{1,2}):0?(\d{1,2})([AP])/);

				if(!t) continue;

				var h = parseInt(t[1]);
				var m = parseInt(t[2]);

				var mins = (((t[3] == "P" ? (h < 12 ? 12+h : h) : (h == 12 ? 0 : h))) * 60) + m;
//				_error_debug("time=" + timelist[j] + ", mins=" + mins);

				// is this the first populated column of this row?
				if(!first_time_of_this_row) {
					first_time_of_this_row = mins;
				}

				// is the current time less than the previous time on this row?
				if(mins < prev_time) {
					into_tomorrow = true;
				}

				var a;
				var day_to_add;
				// once the time rolls past midnight, add them to tomorrow's list instead
				if(mins > station_current_mins[j] && !(first_time_of_this_row < first_time_of_prev_row) && into_tomorrow != true) {
					switch(which_day) {
					case 'SA':
						day_to_add = 6;
						break;
					case 'SU':
						day_to_add = 0;
						break;
					default:
						day_to_add = which_day;
					}
					station_current_mins[j] = mins;
				} else if(which_day == 'WK') {
					day_to_add = 'WKM';
				} else if(which_day == 'SA') {
					day_to_add = 0;
				} else if(which_day == 'SU') {
					day_to_add = 1;
				}

//				_error_debug("adding " + mins + " to " + day_to_add);

				if(day_to_add == 'WK') {
					for(var k=1; k<=5; k++) {
						a = station["time_points"][k];
						a.push(mins);
					}
				} else if(day_to_add == 'WKM') {
					for(var k=2; k<=6; k++) {
						a = station["time_points"][k];
						a.push(mins);
					}
				} else {
					a = station["time_points"][day_to_add];
					a.push(mins);
				}
				
				prev_time = mins;
			}

			first_time_of_prev_row = first_time_of_this_row;
		}
	}
}

function updateStationList()
{
	_error_debug('update_station_list()');

	$('station').options.length = 0;

	for(var i in station_list) {
		if(!station_list.hasOwnProperty(i)) continue;

		// if a short name is set, use it.  this will not be true only if this is the first time the control is being loaded
		$('station').options[$('station').options.length] = 
			new Option(station_list[i]["name"], i,
				(station_short_name ? station_short_name==station_list[i]["short_name"] : station==i)
				);
	}

	// now that data has been loaded, set the value in the global, since it's probably changed
	station = $('station').value;
	station_short_name = station_list[$('station').value]["short_name"];

}

/*
 * Returns the current day number (0-6)
 */
function getCurrentDay()
{
	var currDate = new Date();

	var day = currDate.getDay();
	
	_error_debug('getCurrentDay(): day=' + day);

	return(day);
}

/*
 * Returns the day number (0-6) of tomorrow
 */
function getNextDay()
{
	var currDate = new Date();

	var day = (currDate.getDay() + 1) % 7;
	
	_error_debug('getNextDay(): day=' + day);

	return(day);
}

/*
 * Returns the url that will be used to get the raw data from the VTA server.
 * Also sets the "More Info" link on the front page.
 */
function setScheduleURL()
{
	_error_debug('setScheduleURL()');

	var day = getCurrentDay();
	var period = (day == 6 ? 'SA' : (day == 0 ? 'SU' : 'WK'));
	
	$('moreLinkAnchor').href = 'http://www.vta.org/schedules/SC_' + line + direction + '_' + period + '.html';
}

/*
 * Given a preference name, returns the key to be used to store the preference.
 */
function createPrefKey(key)
{
	return widget.identifier + "-" + key;
}

/*
 * Saves the settings for next reload of this widget.
 */
function updatePrefs()
{
	_error_debug('updatePrefs()');

	if(window.widget) {
		widget.setPreferenceForKey(line, createPrefKey("line"));
		widget.setPreferenceForKey(direction, createPrefKey("direction"));
		widget.setPreferenceForKey(station, createPrefKey("station"));
	}
}

/*
 * Updates only the static elements on the front page.
 */
function updateStaticFront()
{
	if(station && station_list.length > 0 && station_list[station]) {
		$('location').innerHTML = 
			station_list[station].name.trim().replace(/ +(Light Rail|Lr|Station|Transit C).*/,"")
		 	+ ", " + (direction == 'NO' ? 'Northbound' : 'Southbound');
	}
}

/*
 * Updates the time on the front page.
 */
function updateFront()
{
	_error_debug('updateFront()');

	setScheduleURL();

	var t = getUpcomingTrain();

	if(t['nextDate']) {
		$('arrivalTime').innerHTML = 'At ' + (t["nextDate"].getHours() < 10 ? '0' : '')
			+ t["nextDate"].getHours() + ':' + (t["nextDate"].getMinutes() < 10 ? '0' : '') + t["nextDate"].getMinutes()
			+ (t['nextMinInTomorrow'] == true ? " tomorrow" : (' (' + t["nextMins"] + " mins)"));
	} else {
		$('arrivalTime').innerHTML = "none";
	}

	if(t['followingDate']) {
		$('nextArrivalTime').innerHTML = t["followingDate"].getHours() + ':' + (t["followingDate"].getMinutes() < 10 ? '0' : '') 
			+ t["followingDate"].getMinutes();
	} else {
		$('nextArrivalTime').innerHTML = "none";
	}

}

function getUpcomingTrain()
{
	_error_debug('getUpcomingTrain()');

	_error_debug('station: ' + station);

	var currTime = new Date;
	var currMin = (currTime.getHours() * 60) + currTime.getMinutes();

	_error_debug('currMin: ' + currMin);

	var nextMinInTomorrow = false;

	var time_points;
	var NOT_FOUND = (60*48);
	
	time_points = station_list[station]["time_points"][getCurrentDay()];
	
	_error_debug('time_points.length: ' + time_points.length);
	var nextMin = NOT_FOUND;
	for(var i in time_points) {
		if(!time_points.hasOwnProperty(i)) continue;
		
		if(time_points[i] > currMin) {
			nextMin = Math.min(nextMin, time_points[i]);
		}
		_error_debug('nextMin: ' + nextMin + ', was compared to ' + time_points[i]);
	}
	
	if(nextMin == NOT_FOUND) {
		_error_debug('checking tomorrow vals for nextMin');
		time_points = station_list[station]["time_points"][getNextDay()];
		
		for(var i in time_points) {
			if(!time_points.hasOwnProperty(i)) continue;
		
			nextMin = Math.min(nextMin, time_points[i]);
			nextMinInTomorrow = true;
			_error_debug('nextMin: ' + nextMin + ', was compared to ' + time_points[i]);
		}
	}

	var followingMin = NOT_FOUND;
	for(var i in time_points) {
		if(!time_points.hasOwnProperty(i)) continue;
		
		if(time_points[i] > nextMin) {
			followingMin = Math.min(followingMin, time_points[i]);
		}
		_error_debug('followingMin: ' + followingMin + ', was compared to ' + time_points[i]);
	}

	if(followingMin == NOT_FOUND && !nextMinInTomorrow) {
		_error_debug('checking tomorrow vals for followingMin');
		time_points = station_list[station]["time_points"][getNextDay()];

		for(var i in time_points) {
			if(!time_points.hasOwnProperty(i)) continue;
		
			followingMin = Math.min(followingMin, time_points[i]);
			_error_debug('followingMin: ' + followingMin + ', was compared to ' + time_points[i]);
		}
	}

	var followingDate;
	var nextDate;

	// if it's still not found, it is going to be tomorrow
	if(followingMin == NOT_FOUND) {
		followingMin = null;
	} else {
		followingDate = new Date();
		followingDate.setHours(Math.floor(followingMin/60));
		followingDate.setMinutes(followingMin%60);
	}

	if(nextMin != NOT_FOUND) {
		nextDate = new Date();
		nextDate.setHours(Math.floor(nextMin/60));
		nextDate.setMinutes(nextMin%60);
	}

	return({
		"nextMins" : (nextMin < currMin ? ((60*24)-currMin)+nextMin : nextMin-currMin),
		"nextMinInTomorrow" : nextMinInTomorrow,
		"nextDate" : nextDate,
		"followingDate" : followingDate
		});

}

